//////////////////////////////////////////////////////////////////////////

#include "network_packets.h"

//////////////////////////////////////////////////////////////////////////

#include <cstring>

//////////////////////////////////////////////////////////////////////////


bool ClientPacket::operator==( const ClientPacket& _rhs )
{
    if (m_KeyFlags == _rhs.m_KeyFlags)
    {
        if (m_KeyFlags & STM::MOUSE1)
            return m_MousePosition == _rhs.m_MousePosition;
        else
            return true;
    }
    else
        return false;
}


//////////////////////////////////////////////////////////////////////////


bool ClientPacket::operator!=( const ClientPacket& _rhs )
{
    return !operator==(_rhs);
}


//////////////////////////////////////////////////////////////////////////


bool ServerPacket::operator==( const ServerPacket& _rhs )
{
    return m_Players == _rhs.m_Players   &&
           m_Bullets == _rhs.m_Bullets;
}


//////////////////////////////////////////////////////////////////////////


bool ServerPacket::operator!=( const ServerPacket& _rhs )
{
    return !operator==(_rhs);
}


//////////////////////////////////////////////////////////////////////////


int ClientPacket::Size() const
{
    return sizeof(unsigned char) +
           sizeof(unsigned int) +
           sizeof(short) * 2;
}

//////////////////////////////////////////////////////////////////////////


void ClientPacket::FromStr( const char* _packet )
{
    int shift = 0;

    // First byte is a client ID
    memcpy( &m_ClientID, &_packet[shift], sizeof(unsigned char));
    shift += sizeof(unsigned char);

    // Next 4 bytes are key flags
    memcpy( &m_KeyFlags, &_packet[shift], sizeof(unsigned int));
    shift += sizeof(unsigned int);

    // Next 2 bytes are X mouse position
    memcpy( &m_MousePosition.first, &_packet[shift], sizeof(short));
    shift += sizeof(short);

    // Next 2 bytes are Y mouse position
    memcpy( &m_MousePosition.second, &_packet[shift], sizeof(short));
    shift += sizeof(short);
}


//////////////////////////////////////////////////////////////////////////


std::vector<char> ClientPacket::ToStr() const
{
    std::vector<char> packet( Size() );
    int shift = 0;

    // First byte is a client ID
    memcpy( &packet[shift], &m_ClientID, sizeof(unsigned char));
    shift += sizeof(unsigned char);

    // Next 4 bytes are key flags
    memcpy( &packet[shift], &m_KeyFlags, sizeof(unsigned int));
    shift += sizeof(unsigned int);
    
    // Next 2 bytes are X mouse position
    memcpy( &packet[shift], &m_MousePosition.first, sizeof(short));
    shift += sizeof(short);

    // Next 2 bytes are Y mouse position
    memcpy( &packet[shift], &m_MousePosition.second, sizeof(short));
    shift += sizeof(short);

    // Return resulting string
    return packet;
}


//////////////////////////////////////////////////////////////////////////


int ServerPacket::Size() const
{
    return
        sizeof(clock_t) +
        m_Players.size() * sizeof(short) * 2 + sizeof(size_t) +
        m_Bullets.size() * sizeof(short) * 2 + sizeof(size_t);
}


//////////////////////////////////////////////////////////////////////////


std::vector<char> ServerPacket::ToStr() const
{
    // Convert memory to string
    std::vector<char> packet(Size());

    int shift = 0;

    // First is a packet creation time
    memcpy( &packet[shift], &m_CreationTime, sizeof(clock_t) );
    shift += sizeof(clock_t);

    // Save players data
    shift += SaveData( m_Players, &packet[shift] );

    // Save bullets data
    shift += SaveData( m_Bullets, &packet[shift] );

    return packet;
}


//////////////////////////////////////////////////////////////////////////


int ServerPacket::SaveData( const STM::ScrPositions& _objects, char* _mem ) const
{
    // Bytes have been written
    int shift = 0;

    size_t objSize = _objects.size();

    // Save number of objects
    memcpy( _mem, &objSize, sizeof(size_t) );
    shift += sizeof(size_t);

    // Save object's coordinates
    for (size_t i = 0; i < _objects.size(); ++i)
    {
        memcpy( _mem + shift, &_objects[i].first, sizeof(short) );
        shift += sizeof(short);

        memcpy( _mem + shift, &_objects[i].second, sizeof(short) );
        shift += sizeof(short);
    }

    return shift;
}


//////////////////////////////////////////////////////////////////////////


void ServerPacket::FromStr( const char* _packet )
{
    int shift = 0;

    // First is a packet creation time
    memcpy( &m_CreationTime, &_packet[shift], sizeof(clock_t) );
    shift += sizeof(clock_t);

    // Load players data
    shift += LoadData( m_Players, _packet + shift );
    
    // Load bullets data
    shift += LoadData( m_Bullets, _packet + shift );
}


//////////////////////////////////////////////////////////////////////////


int ServerPacket::LoadData( STM::ScrPositions& _objects, const char* _mem )
{
    // Next 4 bytes are objects count
    size_t objectsCount = 0;

    int shift = 0;

    memcpy( &objectsCount, &_mem[shift], sizeof(size_t));
    shift += sizeof(size_t);

    _objects.resize(objectsCount);

    // Next objectsCount*2*2 bytes are objects coordinates
    for (size_t i = 0; i < objectsCount; ++i)
    {
        memcpy( &_objects[i].first, &_mem[shift], sizeof(short));
        shift += sizeof(short);

        memcpy( &_objects[i].second, &_mem[shift], sizeof(short));
        shift += sizeof(short);
    }

    return shift;
}


//////////////////////////////////////////////////////////////////////////
